from marketdata import statistic
from mapper import Mapper
from marketdata.models import *
from datetime import  date, datetime, timedelta
import logging
import sys

class StatCompactor(Mapper):
    KIND = MarketHistory

    def __init__(self):
        Mapper.__init__(self)
        self.enddate = date.today()
        logging.debug("compactor.init: today %s" % (str(self.enddate)))
        if self.enddate.month < 4:
            self.enddate = self.enddate.replace(self.enddate.year-1, self.enddate.month+9, self.enddate.day)
        else:
            self.enddate = self.enddate.replace(self.enddate.year, self.enddate.month-3, self.enddate.day)
        logging.debug("compactor.init: enddate %s weekday %s" % (self.enddate,self.enddate.isoweekday()))
        if self.enddate.isoweekday() != 7:
            startweekday = timedelta(-self.enddate.isoweekday())
            logging.debug("compactor.map: startweekday %s" % (startweekday))
            self.enddate = self.enddate + startweekday
        logging.info("compactor.init: final enddate %s weekday %s" % (self.enddate, self.enddate.isoweekday()))
        self.ancestor = None
        self.workenddate = None
        self.temp = []
        self.delay = 10


    def map(self,key):
        ToDelete = []
        ToPut = []
        cdate = datetime.strptime(key.name()[15:25],"%Y-%m-%d").date()
        logging.debug("compactor.map: key.name %s" % (key.name()))
        logging.debug("compactor.map: cdate %s" % (str(cdate)))
        logging.debug("compactor.map: enddate %s" % (self.enddate))
        if (cdate <= self.enddate):
            if not self.ancestor:
                self.ancestor = key.name()[0:15]
            logging.debug("compactor.map: ancestor %s" % (self.ancestor))
            logging.debug("compactor.map: wedate %s" % (self.workenddate))
            logging.debug("compactor.map: len temp %s" % (str(len(self.temp))))
            if (len(self.temp) == 0):
                logging.debug("compactor.map: first item in temp")
                cweekday = timedelta(7-cdate.isoweekday() )
                self.workenddate=cdate + cweekday
                if self.workenddate > self.enddate:
                    self.workenddate = self.enddate
                logging.debug("compactor.map: wedate %s, weekday %s" % (self.workenddate, self.workenddate.isoweekday()))
                self.temp=[key]
                logging.debug("compactor.map: temp inited %s" % (str(len(self.temp))))
            elif (key.name()[0:15] == self.ancestor) and (cdate <= self.workenddate):
                logging.debug("compactor.map: possible next item in temp")
                if cdate <= self.workenddate:
                    self.temp.append(key)
                    logging.debug("compactor.map: temp added %s" % (str(len(self.temp))))
            if ((cdate >= self.workenddate) or (key.name()[0:15] != self.ancestor) or (cdate >= self.enddate)) and (len(self.temp) > 0):
                logging.debug("compactor.map: possible last item in temp")
                logging.debug("compactor.map: temp %s" % (str(len(self.temp))))
                cHistory = None
                historykey = self.ancestor+self.workenddate.isoformat()
                logging.debug("compactor.map: historykey %s" % (str(historykey)))
                if (len(self.temp) > 1) or (datetime.strptime(self.temp[0].name()[15:25],"%Y-%m-%d").date().weekday() != 6):
                    for tkey in self.temp:
                        tHistory = MarketHistory.get(tkey)
                        if cHistory == None:
                            cHistory = MarketHistory(typeID = tHistory.typeID, 
                                                     solarSystemID = tHistory.solarSystemID,
                                                     date = self.workenddate, 
                                                     key_name = historykey)
                        cHistory.updated = tHistory.updated
                        if tHistory.ordersSell > 0:
                            if cHistory.ordersSell > 0:
                                if cHistory.ordersSell < tHistory.ordersSell:
                                    cHistory.ordersSell = tHistory.ordersSell
                                if cHistory.minSellPrice > tHistory.minSellPrice:
                                    cHistory.minSellPrice = tHistory.minSellPrice
                                if cHistory.maxSellPrice < tHistory.maxSellPrice:
                                    cHistory.maxSellPrice = tHistory.maxSellPrice
                                cHistory.averageSellPrice = (tHistory.averageSellPrice + cHistory.averageSellPrice) / 2
                                cHistory.medianSellPrice = (tHistory.medianSellPrice + cHistory.medianSellPrice) / 2
                                if cHistory.volSellRemaining > tHistory.volSellRemaining:
                                    cHistory.volSellRemaining = tHistory.volSellRemaining
                                if cHistory.volSellEntered < tHistory.volSellEntered:
                                    cHistory.volSellEntered = tHistory.volSellEntered
                                if cHistory.newestSellOrder:
                                    if (tHistory.newestSellOrder) and (cHistory.newestSellOrder < tHistory.newestSellOrder):
                                        cHistory.newestSellOrder = tHistory.newestSellOrder
                                else:
                                    cHistory.newestSellOrder = tHistory.newestSellOrder
                                if cHistory.oldestSellOrder:
                                    if (tHistory.oldestSellOrder) and (cHistory.oldestSellOrder > tHistory.oldestSellOrder):
                                        cHistory.oldestSellOrder = tHistory.oldestSellOrder
                                else:
                                    cHistory.oldestSellOrder = tHistory.oldestSellOrder
                            else:
                                cHistory.ordersSell = tHistory.ordersSell
                                cHistory.minSellPrice = tHistory.minSellPrice
                                cHistory.maxSellPrice = tHistory.maxSellPrice
                                cHistory.averageSellPrice = tHistory.averageSellPrice
                                cHistory.medianSellPrice = tHistory.medianSellPrice
                                cHistory.volSellRemaining = tHistory.volSellRemaining
                                cHistory.volSellEntered = tHistory.volSellEntered
                                cHistory.newestSellOrder = tHistory.newestSellOrder
                                cHistory.oldestSellOrder = tHistory.oldestSellOrder

                        if tHistory.ordersBuy > 0:
                            if cHistory.ordersBuy > 0:
                                if cHistory.ordersBuy < tHistory.ordersBuy:
                                    cHistory.ordersBuy = tHistory.ordersBuy
                                if cHistory.minBuyPrice > tHistory.minBuyPrice:
                                    cHistory.minBuyPrice = tHistory.minBuyPrice
                                if cHistory.maxBuyPrice < tHistory.maxBuyPrice:
                                    cHistory.maxBuyPrice = tHistory.maxBuyPrice
                                cHistory.averageBuyPrice = (tHistory.averageBuyPrice + cHistory.averageBuyPrice) / 2
                                cHistory.medianBuyPrice = (tHistory.medianBuyPrice + cHistory.medianBuyPrice) / 2
                                if cHistory.volBuyRemaining > tHistory.volBuyRemaining:
                                    cHistory.volBuyRemaining = tHistory.volBuyRemaining
                                if cHistory.volBuyEntered < tHistory.volBuyEntered:
                                    cHistory.volBuyEntered = tHistory.volBuyEntered
                                if cHistory.newestBuyOrder:
                                    if (tHistory.newestBuyOrder) and (cHistory.newestBuyOrder < tHistory.newestBuyOrder):
                                        cHistory.newestBuyOrder = tHistory.newestBuyOrder
                                else:
                                    cHistory.newestBuyOrder = tHistory.newestBuyOrder
                                if cHistory.oldestBuyOrder:
                                    if (tHistory.oldestBuyOrder) and (cHistory.oldestBuyOrder > tHistory.oldestBuyOrder):
                                        cHistory.oldestBuyOrder = tHistory.oldestBuyOrder
                                else:
                                    cHistory.oldestBuyOrder = tHistory.oldestBuyOrder
                            else:
                                cHistory.ordersBuy = tHistory.ordersBuy
                                cHistory.minBuyPrice = tHistory.minBuyPrice
                                cHistory.maxBuyPrice = tHistory.maxBuyPrice
                                cHistory.averageBuyPrice = tHistory.averageBuyPrice
                                cHistory.medianBuyPrice = tHistory.medianBuyPrice
                                cHistory.volBuyRemaining = tHistory.volBuyRemaining
                                cHistory.volBuyEntered = tHistory.volBuyEntered
                                cHistory.newestBuyOrder = tHistory.newestBuyOrder
                                cHistory.oldestBuyOrder = tHistory.oldestBuyOrder
                        if cHistory.date == tHistory.date:
                            logging.info("compactor.map: before to update %s" % (tHistory))
                            tHistory.ordersSell = cHistory.ordersSell
                            tHistory.minSellPrice = cHistory.minSellPrice
                            tHistory.maxSellPrice = cHistory.maxSellPrice
                            tHistory.averageSellPrice = cHistory.averageSellPrice
                            tHistory.medianSellPrice = cHistory.medianSellPrice
                            tHistory.volSellRemaining = cHistory.volSellRemaining
                            tHistory.volSellEntered = cHistory.volSellEntered
                            tHistory.newestSellOrder = cHistory.newestSellOrder
                            tHistory.oldestSellOrder = cHistory.oldestSellOrder
                            tHistory.ordersBuy = cHistory.ordersBuy
                            tHistory.minBuyPrice = cHistory.minBuyPrice
                            tHistory.maxBuyPrice = cHistory.maxBuyPrice
                            tHistory.averageBuyPrice = cHistory.averageBuyPrice
                            tHistory.medianBuyPrice = cHistory.medianBuyPrice
                            tHistory.volBuyRemaining = cHistory.volBuyRemaining
                            tHistory.volBuyEntered = cHistory.volBuyEntered
                            tHistory.newestBuyOrder = cHistory.newestBuyOrder
                            tHistory.oldestBuyOrder = cHistory.oldestBuyOrder
                            cHistory = tHistory
                            logging.info("compactor.map: to update %s" % (cHistory))
                        else:     
                            ToDelete.append(tHistory.key()) 
                            logging.info("compactor.map: to del %s" % (tHistory))
                if cHistory:
                    ToPut.append(cHistory)
                    logging.info("compactor.map: to put %s" % (cHistory))
                    self.temp=[]
                    logging.debug("compactor.map: temp cleaned %s" % (str(len(self.temp))))
                if ((cdate > self.workenddate) or (key.name()[0:15] != self.ancestor)) and (cdate <= self.enddate):
                    self.ancestor = key.name()[0:15]
                    logging.debug("compactor.map: reinit ancestor %s" % (self.ancestor))
                    if cdate > self.workenddate:
                        self.temp=[key]
                    logging.debug("compactor.map: temp inited %s" % (str(len(self.temp))))
                    cweekday = timedelta(7 - cdate.isoweekday())
                    self.workenddate=cdate + cweekday
                    if self.workenddate > self.enddate:
                        self.workenddate = self.enddate
                    logging.debug("compactor.map: wedate %s" % (str(self.workenddate)))
        if (cdate > self.enddate) and (len(self.temp) > 0):
            self.temp =  []
            logging.debug("compactor.map: temp cleaned %s" % (str(len(self.temp))))
        logging.debug("compactor.map: return toPut %s, toDelete %s" % (str(len(ToPut)),str(len(ToDelete))))
        return (ToPut, ToDelete)

    def _batch_write(self, key=None):
        """Writes updates and deletes entities in a batch."""
        if key and key.has_id_or_name():
            logging.debug("batch_write: last key %s" % (key.id_or_name()))
        else:
            logging.debug("batch_write: last key %s" % (key))
        if self.to_delete:
            logging.debug("batch_write: to_delete %d" % (len(self.to_delete)))
            try:
            	db.delete(self.to_delete)                              
            except:
            	logging.warning("continue: exception %s, %s" % (sys.exc_info()[:1],str(sys.exc_info()[1:2]))) 
            	for tkey in self.to_delete:
            	    if tkey and tkey.has_id_or_name():
                        logging.debug("batch_write: to_delete item %s" % (tkey.id_or_name()))
                        if self.KIND.get(tkey) :
                            db.delete(tkey)
                            logging.debug("batch_write: deleted")
            self.to_delete = []
        if (len(self.temp) > 0)  and self.temp[len(self.temp)-1]: 
            key=self.temp[len(self.temp)-1]
            if key.has_id_or_name():
                logging.info("batch_write: replace last key with %s" % (key.id_or_name()))
            else:
                logging.info("batch_write: replace last key with %s" % (key))
            self.temp =  []
        self.start_key = key
        if self.to_put:
            logging.debug("batch_write: to_put %d" % (len(self.to_put)))
            db.put(self.to_put)
            self.to_put=[]
        if self.start_key and self.start_key.has_id_or_name():
            logging.debug("batch_write: done, next first key %s" % (self.start_key.id_or_name()))
        else:
            logging.debug("batch_write: done, next first key %s" % (self.start_key))
